package com.xing.config;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.xing.exception.BusinessException;
import com.xing.utils.Result;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;

import java.net.BindException;
import java.util.List;

/**
 * @version 1.0
 * @Author Xing
 * @Date 2024/7/14 10:06
 * @deprecated 全局异常抛出
 */
@RestControllerAdvice
@Slf4j
@Configuration
public class GlobalExceptionHandler {

    private final HttpServletRequest request;

    public GlobalExceptionHandler(HttpServletRequest request) {
        this.request = request;
    }


    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handle(MissingServletRequestParameterException e, HandlerMethod handlerMethod) {
        logInfo(e, handlerMethod);

        String parameterDescription = getParameterDescription(e, handlerMethod);
        String userMessage = String.format("[%s] 参数缺失，此参数为必传参数", parameterDescription);
        String errorMessage = String.format("【参数校验异常】：%s", e.getMessage());
        return new Result().err(400, userMessage + String.valueOf(HttpStatus.BAD_REQUEST.value()) + errorMessage);
    }


    private String getParameterDescription(MissingServletRequestParameterException e, HandlerMethod handlerMethod) {
        String parameterName = e.getParameterName();
        String parameterDescription = parameterName;

        Parameter[] annotationsByType = handlerMethod.getMethod().getAnnotationsByType(Parameter.class);
        for (Parameter parameter : annotationsByType) {
            String name = parameter.name();
            if (name != null && name.equals(parameterName)) {
                String description = parameter.description();
                if (StringUtils.hasText(description)) {
                    parameterDescription = description;
                }
                break;
            }
        }
        return parameterDescription;
    }


    @ExceptionHandler
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Result handle(HttpRequestMethodNotSupportedException e) {
        // 注意：此方法不能包含 HandlerMethod 入参，否则会报错；因为这个异常处理代表着没找到接口，自然也就没有接口对应的方法。
        logInfo(e);

        String api = getApi();
        String userMessage = "接口请求异常！请稍后重试，或联系业务人员处理。";
        String errorMessage = String.format("【Http请求方法不支持异常】：接口 %s 不存在；报错信息：[org.springframework.web.HttpRequestMethodNotSupportedException: %s]", api, e.getMessage());
        log.error(errorMessage);
        return new Result().err(400, userMessage);
    }

    @ExceptionHandler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Result handle(HttpMessageNotReadableException e, HandlerMethod handlerMethod) {
        logInfo(e, handlerMethod);
        String errorMessage = String.format("HttpMessageNotReadableException（Http消息不可读异常）：%s", e.getMessage());
        return new Result().err(400, errorMessage);
    }

    /**
     * 业务异常处理
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handle(BusinessException e, HandlerMethod handlerMethod) {
        logInfo(e, handlerMethod);
        return new Result().err(400, e.getErrorMessage());
    }

    /**
     * 兜底异常处理
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handle(Throwable e, HandlerMethod handlerMethod) {
        logError(e, handlerMethod);
        return new Result().err(400, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
    }

    private void logInfo(Throwable e) {
        String exceptionName = e.getClass().getName();
        String requestMethod = request.getMethod();
        String url = request.getRequestURI();
        String message = String.format("\n接口：[%s:%s]\n异常名称：[%s]\n异常信息：\n%s", requestMethod, url, exceptionName, e.getMessage());
        log.info(message, e);
    }

    private void logInfo(Throwable e, HandlerMethod handlerMethod) {
        String message = getLogMessage(e, handlerMethod);
        log.info(message, e);
    }

    private void logError(Throwable e, HandlerMethod handlerMethod) {
        String message = getLogMessage(e, handlerMethod);
        log.error(message, e);
    }

    private String getLogMessage(Throwable e, HandlerMethod handlerMethod) {
        String exceptionName = e.getClass()
                .getName();
        String requestMethod = request.getMethod();
        String url = request.getRequestURI();
        String className = handlerMethod.getBean()
                .getClass()
                .getName();
        String methodName = handlerMethod.getMethod()
                .getName();

        return String.format("\n接口：[%s:%s]\n异常名称：[%s]\n出现异常的方法：[%s.%s]\n异常信息：\n%s", requestMethod, url, exceptionName, className, methodName, e.getMessage());
    }

    private String getApi() {
        String requestMethod = request.getMethod();
        String url = request.getRequestURI();
        return String.format("[%s:%s]", requestMethod, url);
    }
}
